package battleship_server;

import battleship_admin.AdminThread;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import battleship_server.threads.*;
import java.sql.SQLIntegrityConstraintViolationException;

/**
 *
 * @author omar
 */
public class SocketConnection extends Thread {

    private Socket client = null;
    private PrintWriter out = null;
    private BufferedReader in = null;
    private String uniqueIDConection = "";
    private PlayerController playerController;
    private String usern = "";
    private int numUsuarioEnJuego = 1;
    private Player player = null;
    public boolean connected = true;
    public boolean keepOn = true;
    public SetShipsThread setShipsThread;
    public GameLogicThread gameLogicThread;
    public AdminThread at = null;

    public SocketConnection(Socket s) {
        client = s;
        playerController = new PlayerController(this);
        try {
            out = new PrintWriter(client.getOutputStream(), true);
            in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        } catch (IOException ex) {
            Logger.getLogger(SocketConnection.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void run() {
        while (connected) {
            try {
                String pp = in.readLine();
                System.out.println("");
                if (pp.equalsIgnoreCase("ping")) {
                    out.println("pong");
                } else if (pp.equalsIgnoreCase("id-request")) {
                    Integer v = generateID();
                    Manager.uniqueIDs.add(v);
                    uniqueIDConection = v.toString();
                    out.println(uniqueIDConection);
                } else if (pp.equalsIgnoreCase("set-id:")) {
                    uniqueIDConection = in.readLine();
                } else if (pp.equalsIgnoreCase("LOGIN")) {
                    parseLogin();
                } else if (pp.equalsIgnoreCase("LOGIN_ADMIN")) {
                    parseLoginAdmin();
                } else if (pp.equalsIgnoreCase("CREATE-USER")) {
                    parseAddUser();
                } else if (pp.equalsIgnoreCase("GET-DATA")) {
                    parseGetData();
                } else if (pp.equalsIgnoreCase("CHANGE-DATA")) {
                    parseChangeUserData();
                } else if (pp.equalsIgnoreCase("GET-USER-NAMES")) {
                    out.println(parseGetUsersNames().toString());
                } else if (pp.equalsIgnoreCase("READY")) {
                    queuePlayer();
                } else if (pp.equalsIgnoreCase("SELECT")) {
                    setShipsThread.selectShips();
                } else if (pp.equalsIgnoreCase("ATTACK")) {
                    int x = Integer.parseInt(in.readLine());
                    int y = Integer.parseInt(in.readLine());
                    gameLogicThread.processMove(x, y);
                } else if(pp.equalsIgnoreCase("GET-SCORES")){
                    getScores();
                }
                Thread.sleep(200);
            } catch (Exception ex) {
                goodbye();
                connected = false;
            }
        }
    }

    public void getScores(){
        out.println(ServerGameController.getInstance().database.retreiveScore(this.player.getUser()));
    }

    public void goodbye() {
        try {
            client.close();
        } catch (IOException ex) {
        } finally {
            Manager.onlineUsers.removeFirstOccurrence(this);
        }
    }

    public Integer generateID() {
        Integer v;
        do {
            v = new Random().nextInt(Integer.MAX_VALUE);
        } while (Manager.uniqueIDs.contains(v));
        return v;
    }

    public void parseLogin() {
        try {
            String username = in.readLine();
            String password = "";
            String receive = "";
            while (!(receive = in.readLine()).equals("END_PASSWORD")) {
                password += receive;
            }
            String lastIPAddress = in.readLine();
            String loginValidation = playerController.validateLogin(username, password);
            if (loginValidation.equals("true")) {
                setPlayer(playerController.login(username, lastIPAddress));
                Manager.onlineUsers.add(this);
                out.println("true");
            } else {
                out.println(loginValidation);
            }
        } catch (IOException ioe) {
        }
    }

    public void parseLoginAdmin() {
        try {
            String username = in.readLine();
            String password = "";
            String receive = "";
            while (!(receive = in.readLine()).equals("END_PASSWORD")) {
                password += receive;
            }
            if (playerController.validateLoginAdmin(username, password)) {
                at = new AdminThread(this);
                at.start();
                out.println("true");
                
            } else {
                out.println("Incorrect Data");
            }
        } catch (IOException ioe) {
        }
    }

    public void parseAddUser() {
        String name = "", username = "", password = "", mail = "", lastIPAddress = "";
        try {
            name = getIn().readLine();
            username = getIn().readLine();
            String receive = "";
            while (!(receive = getIn().readLine()).equals("END_PASSWORD")) {
                password += receive;
            }
            mail = in.readLine();
            lastIPAddress = getIn().readLine();
            try {
                if (ServerGameController.getInstance().database.playerExists(username)) {
                    out.println("The user already exists.");
                } else if (playerController.addPlayer(name, username, password, mail, lastIPAddress)) {
                    setPlayer(playerController.login(username, lastIPAddress));
                    Manager.onlineUsers.add(this);
                    out.println("true");
                } else {
                    out.println("Error en el servicio de login");
                }
            } catch (SQLIntegrityConstraintViolationException sqle) {
                out.println("false");
                out.println("That user already exists!");
            } catch (Exception e) {
                out.println("false");
                out.println("Error when creating the user.");
            }
        } catch (IOException ioe) {
        }
    }

    public void parseGetData() {
        out.println(getPlayer().getName());
        out.println(getPlayer().getUser());
        out.println(getPlayer().getPassword());
        out.println(getPlayer().getMail());
    }

    public void parseChangeUserData() {
        String name = "", username = "", password = "", mail = "";
        try {
            name = in.readLine();
            username = in.readLine();
            String receive = "";
            while (!(receive = getIn().readLine()).equals("END_PASSWORD")) {
                password += receive;
            }
            mail = in.readLine();
            try {
                if (ServerGameController.getInstance().database.updatePlayer(name, username, password, mail) == 1) {
                    getPlayer().setName(name);
                    getPlayer().setPassword(password);
                    getPlayer().setMail(mail);
                    out.println("true");
                } else {
                    out.println("Error when updating data.");
                }
            } catch (Exception e) {
                out.println("false");
                out.println("Error al crear el usuario, verifique los datos");
            }
        } catch (IOException ioe) {
        }
    }

    public void queuePlayer() {
        ServerGameController.getInstance().queuePlayer(this);
    }

    public ArrayList parseGetUsersNames() {
        ArrayList userNames = new ArrayList();
        userNames = Manager.getOnlineListUsers();
        return userNames;
    }

    /**
     * @return the uniqueIDConection
     */
    public String getIdUnicoConexion() {
        return uniqueIDConection;
    }

    /**
     * @return the uniqueIDConection
     */
    public int getIdUnicoConexionInt() {
        return Integer.parseInt(uniqueIDConection);
    }

    /**
     * @return the out
     */
    public PrintWriter getOut() {
        return out;
    }

    /**
     * @return the in
     */
    public BufferedReader getIn() {
        return in;
    }

    /**
     * @return the player
     */
    public Player getPlayer() {
        return player;
    }

    /**
     * @param player the player to set
     */
    public void setPlayer(Player player) {
        this.player = player;
    }
}
